package smetana.modules.business.interceptor;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.ibatis.session.SqlSession;
import smetana.ibatis.SqlSessionProvider;
import smetana.modules.business.SqlSessionInjectable;
import smetana.modules.business.meta.Commit;

import java.util.IdentityHashMap;

/**
 * @author dmitry.mamonov
 */
public class IBatisMethodInterceptor implements MethodInterceptor {
    final boolean debug = false;

    IdentityHashMap<Object, Boolean> applied = new IdentityHashMap<Object, Boolean>();

    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        if (mi.getMethod().getDeclaringClass() == Object.class) {
            return mi.proceed();
        }
        if (applied.containsKey(mi.getThis()) == true) {
            return mi.proceed();
        } else {
            applied.put(mi.getThis(), Boolean.TRUE);
            try {
                if (debug == true) {
                    System.out.println("begin>>");
                }
                SqlSession sql = SqlSessionProvider.getInstance().openSession(); //TODO как не не по guice-овски здесь.
                try {
                    SqlSessionInjectable injectable = (SqlSessionInjectable) mi.getThis();
                    injectable.setSqlSession(sql);
                    try {
                        if (debug == true) {
                            System.out.println("call: " + mi.getMethod().getName());
                        }
                        Object result = mi.proceed();
                        if (mi.getMethod().getAnnotation(Commit.class) != null) {
                            sql.commit();
                        }
                        return result;
                    } finally {
                        injectable.setSqlSession(null);
                    }
                } finally {
                    sql.close();
                    if (debug == true) {
                        System.out.println("end<<");
                    }
                }
            } finally {
                applied.remove(mi.getThis());
            }
        }
    }
}
